﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Windows;

namespace D3UnidPredict
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : INotifyPropertyChanged
	{
		private string _unidHurl;
		public string UnidHurl
		{   
			get { return _unidHurl; }
			set
			{
				_unidHurl = value;
				NotifyPropertyChanged(() => UnidHurl);
			}
		}

		private string _idHurl;
		public string IdHurl
		{
			get { return _idHurl; }
			set
			{
				_idHurl = value;
				NotifyPropertyChanged(() => IdHurl);
			}
		}
		
		private ObservableCollection<string> _stats;
		public ObservableCollection<string> Stats
		{
			get { return _stats; }
			set
			{
				_stats = value;
				NotifyPropertyChanged(() => Stats);
			}
		}

		public MainWindow()
		{
			InitializeComponent();

			Stats = new ObservableCollection<string>();

            if (!File.Exists("AffixToStat.txt"))
                File.WriteAllText("AffixToStat.txt", Properties.Resources.AffixToStat);
            if (!File.Exists("CodeToAffix.txt"))
                File.WriteAllText("CodeToAffix.txt", Properties.Resources.CodeToAffix);
		}

		private void btnUnid_Click(object sender, RoutedEventArgs e)
		{
            if (UnidHurl.Split(':').Length != 18)
            {
                MessageBox.Show("Invalid input.");
                return;
            }
			var codes = ExtractLookupCodes(UnidHurl);
            if (codes == null)
                return;
			var affixes = codes.Select(LookupAffix);
            IdHurl = GetIdHurl(UnidHurl);
			Stats = new ObservableCollection<string>(affixes.Select(RequestStat));
		}

		private void btnCopyChar_Click(object sender, RoutedEventArgs e)
		{
			Clipboard.SetData(DataFormats.UnicodeText, "ㅇ");
		}

		private void btnCopyIdHurl_Click(object sender, RoutedEventArgs e)
		{
			Clipboard.SetData(DataFormats.UnicodeText, IdHurl);
		}

		private static IEnumerable<string> ExtractLookupCodes(string unidHurl)
		{
			List<string> res = new List<string>();
			try
			{
				res = unidHurl.Split(':')[3].Split(',').ToList();
			}
			catch
			{
				MessageBox.Show("Invalid input.");
			    return null;
			}
			return res;
		}

		private static string LookupAffix(string code)
		{
			using (var reader = new StreamReader("CodeToAffix.txt"))
			{
				string line;
				while ((line = reader.ReadLine()) != null)
				{
					if (line.Contains(code))
					{
						return line.Substring(code.Length+1);
					}
				}
			}
			return string.Empty;
		}

		private static string RequestStat(string affix)
		{
			if (string.IsNullOrEmpty(affix) || affix.Contains("Unknown"))
				return "Unknown Suffix/Affix - use the Auction House!";
            using (var reader = new StreamReader("AffixToStat.txt"))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    if (line.Split(';')[0] == affix)
                        return line.Contains("No information") ? null : line.Split(';')[1];
                }
            }
		    return null;
		}

		private string GetIdHurl(string unidHurl)
		{
			var affixes = ExtractLookupCodes(unidHurl).ToList();
			affixes.Reverse();
			
			var parts = unidHurl.Split(':');
			// remove possibly pasted char before the hurl
			parts[0] = "|HItem";
			parts[3] = String.Join(",", affixes);
			parts[9] = (int.Parse(parts[9]) | 0x1).ToString();

			var numbers = new string[parts.Length - 3];
			for(int i = 1; i < parts.Length - 2; i++)
				numbers[i - 1] = parts[i];

			string hashInput = String.Join(":", numbers) + ":";
			var linkHash = (Int32)HashString(hashInput);
			parts[parts.Length-2] = linkHash.ToString();
			
			return String.Join(":", parts);
		}

		private static uint HashString(string s)
		{
			uint h = 0;
			foreach (int c in s)
				h = (uint)((h * 0x21) + c);
			return h;
		}

		#region implementation of INotifyPropertyChanged
		public event PropertyChangedEventHandler PropertyChanged;

		/// <summary>
		/// Generic wrapper implementation to propagate a property change w/o the need to specify hardcoded name strings.
		/// The lambda expression does not need any parameters!
		/// </summary>
		/// <example>NotifyPropertyChanged(() => MyProperty);</example>
		protected void NotifyPropertyChanged<T>(Expression<Func<T>> exp)
		{
			MemberExpression memberExpression = (MemberExpression)exp.Body;
			string propertyName = memberExpression.Member.Name;
			NotifyPropertyChanged(propertyName);
		}

		protected void NotifyPropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
		}
		#endregion
	}
}
